﻿using Checkpoint2XNA.Utilities;
using Microsoft.Xna.Framework;
using System;
using System.Diagnostics;
using Checkpoint2XNA.Models.Chess;

namespace Checkpoint2XNA.Models
{


    public static class ChessModelManager
    {
        const float BOARD_SIZE = 3.9f;
        const float EXTRA_SEARCH_SPACE = .3f;
        const float CELL_SIZE = BOARD_SIZE / 8.0f;
        const float ANIMATION_SPEED = .000001f;
        const float MIN_ANIM_DISTANCE = .01f;
        const float DISTANCE_TO_HEAVEN = 1f;

        public static bool animating = false;
        public static Model3D animatedModel = null;
        public static Vector3 animatedDestination;
        public static int animatedGridIndexDest;
        public static Vector3 animatedVector;
        

        //private static Vector3 outerMin = new Vector3(-2f - EXTRA_SEARCH_SPACE, -4.1f, -6f - EXTRA_SEARCH_SPACE);
        //private static Vector3 outerMax = new Vector3(-2f + BOARD_SIZE + EXTRA_SEARCH_SPACE, -8f, -6f + BOARD_SIZE + .5f);
        private static Vector3 outerMin = new Vector3(-2f - EXTRA_SEARCH_SPACE, -4f, -6.2f);
        private static Vector3 outerMax = new Vector3(-2f + BOARD_SIZE + EXTRA_SEARCH_SPACE, -5f, -6.0f + BOARD_SIZE);



        //private static Model3D[] grid;
        private static CheckerPlane plane = new CheckerPlane(new Vector3(-2f, -4f, -5.5f),
                                                BOARD_SIZE,
                                                Color.Black, Color.White);
        public static void InitializePieces()
        {
            QuadTree.ConstructTree(plane.Pos, CELL_SIZE, 2);

            QuadTree.grid = new Model3D[64];
            QuadTree.grid[0] = new Rook(GetGridPoint(0), CELL_SIZE, ChessSide.Black);
            QuadTree.grid[1] = new Knight(GetGridPoint(1), CELL_SIZE, ChessSide.Black);
            QuadTree.grid[2] = new Bishop(GetGridPoint(2), CELL_SIZE, ChessSide.Black);
            QuadTree.grid[3] = new King(GetGridPoint(3), CELL_SIZE, ChessSide.Black);
            QuadTree.grid[4] = new Queen(GetGridPoint(4), CELL_SIZE, ChessSide.Black);
            QuadTree.grid[5] = new Bishop(GetGridPoint(5), CELL_SIZE, ChessSide.Black);
            QuadTree.grid[6] = new Knight(GetGridPoint(6), CELL_SIZE, ChessSide.Black);
            QuadTree.grid[7] = new Rook(GetGridPoint(7), CELL_SIZE, ChessSide.Black);

            for (int i = 8; i < 16; i++)
            {
                QuadTree.grid[i] = new Pawn(GetGridPoint(i), CELL_SIZE, ChessSide.Black);
            }


            QuadTree.grid[63] = new Rook(GetGridPoint(63), CELL_SIZE, ChessSide.Shiny);
            QuadTree.grid[62] = new Knight(GetGridPoint(62), CELL_SIZE, ChessSide.Shiny);
            QuadTree.grid[61] = new Bishop(GetGridPoint(61), CELL_SIZE, ChessSide.Shiny);
            QuadTree.grid[60] = new King(GetGridPoint(60), CELL_SIZE, ChessSide.Shiny);
            QuadTree.grid[59] = new Queen(GetGridPoint(59), CELL_SIZE, ChessSide.Shiny);
            QuadTree.grid[58] = new Bishop(GetGridPoint(58), CELL_SIZE, ChessSide.Shiny);
            QuadTree.grid[57] = new Knight(GetGridPoint(57), CELL_SIZE, ChessSide.Shiny);
            QuadTree.grid[56] = new Rook(GetGridPoint(56), CELL_SIZE, ChessSide.Shiny);

            for (int i = 55; i >= 48; i--)
            {
                QuadTree.grid[i] = new Pawn(GetGridPoint(i), CELL_SIZE, ChessSide.Shiny);
            }
        }

        public static void MovePiece(Model3D model, int gridIndex)
        {
            RemovePiece(model);
            animating = true;
            animatedModel = model;
            animatedDestination = GetGridPoint(gridIndex);
            animatedGridIndexDest = gridIndex;
            animatedVector = animatedDestination - model.CenterBottom;
            animatedVector.Normalize();
            Vector3.Multiply(animatedVector, ANIMATION_SPEED);
        }

        public static void RemovePiece(Model3D model)
        {
            for (int i = 0; i < QuadTree.grid.Length; i++)
            {
                if (QuadTree.grid[i] == model)
                    QuadTree.grid[i] = null;
            }
        }

        public static void KillPiece(Model3D model)
        {
            RemovePiece(model);
            animating = true;
            animatedModel = model;
            animatedDestination = new Vector3(model.CenterBottom.X, model.CenterBottom.Y + DISTANCE_TO_HEAVEN, model.CenterBottom.Z);
            animatedGridIndexDest = -1;
            animatedVector = animatedDestination - model.CenterBottom;
            animatedVector.Normalize();
            Vector3.Multiply(animatedVector, ANIMATION_SPEED);
        }

        //get the center of the square which contains point
        public static int GetGridIndexByPoint(Vector3 point)
        {
            var offset = point - plane.Pos;
            int x = (int)(offset.X / CELL_SIZE);
            int z = (int)(offset.Z / CELL_SIZE);
            return 8 * z + x;
        }


        public static Vector3 GetGridPoint(int gridIndex)
        {
            var x = (gridIndex % 8) * CELL_SIZE;
            var z = (gridIndex / 8) * CELL_SIZE;
            var half = CELL_SIZE * .5f;
            return new Vector3(plane.Pos.X + x + half, plane.Pos.Y, plane.Pos.Z + z + half);
        }


       

        public static Tuple<Model3D, double> RayCollide(Vector3 origin, Vector3 ray)
        {
            double t = 0;
            if((t = Collisions.BoxCollide(origin, ray, new Vector3(1.0f / ray.X, 1.0f / ray.Y, 1.0f / ray.Z), new BoxStruct() { Max = outerMax, Min = outerMin})) > 0)
            {
                //return Tuple.Create<Model3D, double>(new Box(new Vector3(), 0, 0, 0, Color.Green), t);
                double temp;
                Tuple<Model3D, double> result = QuadTree.RayCollide(origin, ray);

                if ((temp = plane.RayCollide(origin, ray)) > 0 && (result == null || temp < result.Item2))
                {
                    //t = temp;
                    //c = plane;
                    result =  Tuple.Create<Model3D, double>(plane, temp);
                }
                if (animatedModel != null)
                {
                    if ((temp = animatedModel.RayCollide(origin, ray)) > 0 && (result == null || temp < result.Item2))
                    {
                        result = Tuple.Create<Model3D, double>(animatedModel, temp);
                    }
                }

                return result;
            }
            return null;
        }


        public static void Update(GameTime time)
        {
            if (animating)
            {
                animatedModel.MoveTo(animatedModel.CenterBottom + Vector3.Multiply(animatedVector, time.ElapsedGameTime.Milliseconds / 1000f));
                if (Vector3.Distance(animatedModel.CenterBottom, animatedDestination) < MIN_ANIM_DISTANCE)
                {
                    animatedModel.MoveTo(animatedDestination);

                    if (animatedGridIndexDest >= 0)
                    {
                        if (QuadTree.grid[animatedGridIndexDest] != null)
                        {
                            var temp = QuadTree.grid[animatedGridIndexDest];
                            QuadTree.grid[animatedGridIndexDest] = animatedModel;
                            KillPiece(temp);
                        }
                        else
                        {
                            QuadTree.grid[animatedGridIndexDest] = animatedModel;
                            animatedModel = null;
                            animating = false;
                        }
                    }
                    else
                    {
                        animatedModel = null;
                        animating = false;
                    }
                }
            }
        }

    }
}
